/**
 * Person.java
 * @author Peter
 */
// $codepro.audit.disable com.instantiations.assist.eclipse.analysis.unusedReturnValue
package edu.gatech.coc.betameisters.people;


import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement; // $codepro.audit.disable unnecessaryImport
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;


import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException; // $codepro.audit.disable unnecessaryImport

import edu.gatech.coc.betameisters.infoholders.Constants.UserType;
import edu.gatech.coc.betameisters.utilities.Database;

/**
 * The Person class, where all users extend to.
 * 
 * @author Peter
 * @version $Revision: 1.0 $
 */

public class Person implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1260896689572472673L;

	/**
	 * Information that all user/people (person) objects should at least contain
	 */
	private String firstName = "";

	/**
	 * Field lastName.
	 */
	private String lastName = "";

	/**
	 * Field userID.
	 */
	private String userID = "";

	/**
	 * Field userPass. User's password
	 */
	private String userPass = "";

	/**
	 * Field isLoggedIn.
	 */
	private boolean isLoggedIn;

	/**
	 * Field Suspended
	 */
	private boolean isSuspened;

	/**
	 * Field MyLogger.
	 */
	protected static final Logger MYLOGGER = Logger.getLogger("Person");
 // $codepro.audit.disable blankLineUsage
	/**
	 * Number generated to append with user in the case of a duplicate user id.
	 */
	// private final int nextNumGen = 1;

	/**
	 * Represents the additional fields needed to be saved on the Database
	 */
	protected String[] additionalFields = { "" };

	static {

		MYLOGGER.setLevel(Level.ALL);
		MYLOGGER.setUseParentHandlers(false);

		try {
			final FileHandler fh = new FileHandler("PersonLog.log");
			MYLOGGER.addHandler(fh);
			final SimpleFormatter formatter = new SimpleFormatter();
			fh.setFormatter(formatter);
		} catch (SecurityException e) {
			MYLOGGER.log(Level.SEVERE,
					"Security Exception creating a file handler", e);
			e.printStackTrace();
		} catch (IOException e) {
			MYLOGGER.log(Level.SEVERE, "IO Exception creating a "
					+ "file handler", e);
			e.printStackTrace();
		}

	}

	/**
	 * Field personType
	 */
	protected UserType personType;

	/**
	 * Constructor that creates a person with no specifics
	 * 
	 * @param fName
	 *            - first name of person
	 * @param lName
	 *            - last name of person
	 * @throws Exception
	 */
	protected Person(final String fName, final String lName) { // $codepro.audit.disable
		this.firstName = fName;
		this.lastName = lName;
		
		// default username is the first letter in the first name
		// joined with the last name
		this.userID = fName.charAt(0) + lName;
		this.userPass = lName;
		this.isLoggedIn = false;
		
		create();
	}

	/**
	 * Default constructor
	 */
	protected Person() {
		this.isLoggedIn = false;
	}
	
	/**
	 * Full constructor for a person that does not get created to the database
	 * @param username username
	 * @param password password
	 * @param firstName first name 
	 * @param lastName last name
	 */
	protected Person(String username, String password, 
			String firstName, String lastName) {
		this.userID = username;
		this.userPass = password;
		this.firstName = firstName;
		this.lastName = lastName;
	}

	/**
	 * Sets first name of person
	 * 
	 * @param firstName
	 *            - first name of person
	 */
	public void setFirstName(String firstName) {
		MYLOGGER.info("Setting first name");

		// Create the update query
		final String firstNameUpdate = "UPDATE " + this.getClass().getSimpleName() + 
		" SET first_name = '" + firstName + 
		"' WHERE username='" + this.getUserID() + "'";
		
		Database.executeUpdateQuery(firstNameUpdate);
		
		this.firstName = firstName;
	}

	/**
	 * Gets the first name of person
	 * 
	 * @return first name of person
	 */
	public String getFirstName() {
		MYLOGGER.info("Getting first name");
		return firstName;
	}

	/**
	 * Sets the last name of person
	 * 
	 * @param lastName
	 *            - last name of person
	 */
	public void setLastName(String lastName) {
		MYLOGGER.info("Setting last name");
		
		// Create the update query
		final String lastNameUpdate = "UPDATE " + this.getClass().getSimpleName() + 
		" SET last_name = '" + lastName + 
		"' WHERE username='" + this.getUserID() + "'";
		
		Database.executeUpdateQuery(lastNameUpdate);
		
		this.lastName = lastName;
	}

	/**
	 * Gets the last name of person
	 * 
	 * @return last name
	 */
	public String getLastName() {
		MYLOGGER.info("Getting last name");
		return lastName;
	}

	/**
	 * Sets a username for person
	 * 
	 * @param userID
	 *            - person's username
	 * @throws Exception
	 */
	public void setUserID(String userID) {
		MYLOGGER.info("Setting username");

		final String nameAttempt = sanitizeUserName(userID);
		
		// we need to change it in the database first or else we lose
		// the link to our database
		
		final String userNameUpdate = "UPDATE " + this.getClass().getSimpleName() + 
		" SET username = '" + nameAttempt + 
		"' WHERE username='" + this.getUserID() + "'";
		
		Database.executeUpdateQuery(userNameUpdate);
		
		this.userID = nameAttempt;
	}

	/**
	 * Handles input error for username
	 * @param nameAttempt username attempted
	 * @return an adjusted username that fits the database
	 */
	private String sanitizeUserName(String nameAttempt) {
		System.out.println("Trying to sanitize " + nameAttempt);
		String goodName = nameAttempt;
		int count = 1;
		
		while(!Database.userNameAvailable(goodName)) {
			goodName = nameAttempt + count;
			count++;
		}
		return goodName;
	}
	/**
	 * Gets the username of person
	 * 
	 * @return username
	 */
	public String getUserID() {
		return userID;
	}

	/**
	 * Assert the logged-in status
	 */
	public void loggedIn() {
		MYLOGGER.info("Person logged in");
		this.isLoggedIn = true;
	}

	/**
	 * Assert the logged-out status
	 */
	public void loggedOut() {
		MYLOGGER.info("Person logged out");
		this.isLoggedIn = false;
	}

	/**
	 * Checks whether the person is logged in or not
	 * 
	 * @return a boolean that tells us if the person is logged in or not
	 */
	public boolean status() { // $codepro.audit.disable
		return isLoggedIn;
	}

	/**
	 * Gets the type of the user
	 * @return the person's type
	 */
	public UserType getUserType(){
		return personType;
	}
	
	/**
	 * Overrides the default toString method
	 * 
	 * @return Person's name
	 */
	public String toString() {
		return this.getLastName() + ", " + this.getFirstName();
	}

	/**
	 * Sets the password for this user.
	 * 
	 * @param encryptPass
	 *            - encrypted password
	 * 
	 */
	public void setUserPass(String encryptPass) {
		MYLOGGER.info("Setting password");
		
		// Create the update query
		final String passwordUpdate = "UPDATE " + this.getClass().getSimpleName() + 
		" SET `password` = '" + encryptPass + 
		"' WHERE username='" + this.getUserID() + "'";
		
		Database.executeUpdateQuery(passwordUpdate);
		this.userPass = encryptPass;
	}

	/**
	 * Gets the user's encrypted password for comparison
	 * @return user's encrypted password
	 */
	public String getUserPass() {
		return userPass;
	}

	/**
	 * @param isSuspened the isSuspened to set
	 */
	public void setSuspened(boolean isSuspened) {
		this.isSuspened = isSuspened;
	}

	/**
	 * @return the isSuspened
	 */
	public boolean isSuspened() {
		return isSuspened;
	}

	/**
	 * Gets the user's account type
	 * @return the person's type
	 */
	public UserType getType(){
		return personType;
	}
	/**
	 * Inserts this person into the database
	 */
	public void create() { // $codepro.audit.disable emptyMethod
		final Connection conn = Database.connect();

		try {
			// generate variable list
			this.userID = this.sanitizeUserName(this.userID);
			// Create an SQL query
			final String sql = "INSERT INTO " + this.getClass().getSimpleName()
					+ "(username, password, first_name, last_name) "
					+ "VALUES (\"" + this.getUserID() + "\",\""
					+ this.getUserPass() + "\", \"" + this.getFirstName()
					+ "\",\"" + this.getLastName() + "\")";

			final PreparedStatement stmt = conn.prepareStatement(sql);

			// execute the query
			stmt.execute();
		}
		// Handle the case of a duplicate username
		catch (MySQLIntegrityConstraintViolationException ex) {
			ex.printStackTrace();
		} catch (SQLException ex) {
			ex.printStackTrace();
			System.err.println(ex.getMessage());
		} finally {
			// close the connection
			Database.closeConnection();
		} 
	}

	/**
	 * Removes this person object from the database
	 * @return true if successful, false otherwise
	 */
	public boolean delete() { // $codepro.audit.disable booleanMethodNamingConvention
		final Connection conn = Database.connect();
		
		boolean result = false;
		
		try {
			// Create a query for deletion
			final Statement st = conn.createStatement();

			MYLOGGER.info("Deleting " + this.getClass().getSimpleName() + " " // $codepro.audit.disable
					+ userID);

			// Execute the query
			st.executeUpdate("DELETE FROM " + this.getClass().getSimpleName()
					+ " WHERE username='" + this.getUserID() + "'");
			
			result = true;
		} catch (SQLException ex) {
			System.err.println(ex.getMessage());
			result = false;
		} finally {
			// close the connection
			Database.closeConnection();
		}
		return result;
	}
}